package com.puzzlebazar.server;

import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.puzzlebazar.client.puzzleinfo.PuzzleInfo;
import com.puzzlebazar.client.puzzleinfo.PuzzleInfo.Status;
import com.puzzlebazar.client.util.TextUtil;

public class PuzzleListFilterBasic extends PuzzleListFilter {

	private String authorEmail = null;
	private Type type = null;
	private Boolean needModelInDatastore = null;
	private Vector<String> genres = null;
	private Vector<Status> statuses = null;

	@Override
	public void setAuthorEmail( String authorEmail ) {
		this.authorEmail = authorEmail;
	}
	
	@Override
	public void setType(Type type) {
		this.type = type;
	}

	@Override
	public void setNeedModelInDatastore( Boolean needModelInDatastore ) {
		this.needModelInDatastore = needModelInDatastore;
	}
	
	@Override
	public void setGenres( Vector<String> genres ) {
		this.genres = genres;
	}
	
	@Override
	public void addGenre( String genre ) {
		assert( genre != null );
		if( genres == null )
			genres = new Vector<String>();
		genres.add( genre );
	}
	
	@Override
	public void setStatuses( Vector<Status> statuses ) {
		this.statuses = statuses;
	}
	
	@Override
	public void addStatus( Status status ) {
		assert( status != null );
		if( statuses == null )
			statuses = new Vector<Status>();
		statuses.add( status );
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public LinkedList<PuzzleInfo> runQuery() {
		
	    String filter = "";
	    String parameters = "";
	    
	    if( authorEmail != null )
	    	filter = TextUtil.addToString( filter, "authorEmail == \"" + authorEmail + "\"", " && ");

	    if( type != null ) {
	    	switch( type ){
	    	case PUZZLE_ONLY:
	    		filter = TextUtil.addToString( filter, "tutorial == false" , " && ");
	    		break;
	    	case TUTORIAL_ONLY:
	    		filter = TextUtil.addToString( filter, "tutorial == true" , " && ");
	    		break;
	    	}
	    }

	    if( needModelInDatastore != null )
	    	filter = TextUtil.addToString( filter, "hasModelInDatastore == " + needModelInDatastore.toString(), " && ");

	    if( genres != null && !genres.isEmpty() ) {
	    	filter = TextUtil.addToString( filter, "genre == desiredGenre", " && ");	    	
	    	parameters = TextUtil.addToString( parameters, "String desiredGenre", ", ");
	    }
	    else {
	    	genres = new Vector<String>();
	    	genres.add(null);
	    }
	    
	    if( statuses != null && !statuses.isEmpty() ) {
	    	filter = TextUtil.addToString( filter, "status == desiredStatus", " && ");
	    	parameters = TextUtil.addToString( parameters, "String desiredStatus", ", ");
	    }
	    else {
	    	statuses = new Vector<Status>();
	    	statuses.add(null);
	    }


	    final PersistenceManager pm = PMF.get().getPersistenceManager();
	    final Query query = pm.newQuery( PuzzleInfoJdo.class );	

	    if( filter.length() != 0 )
	    	query.setFilter( filter );
	    if( parameters.length() != 0 )
	    	query.declareParameters( parameters );
		query.setOrdering( "datePublished DESC, dateEdited DESC, dateCreated DESC" );
	    
		LinkedList<PuzzleInfo> result = new LinkedList<PuzzleInfo>();
		try {
			for (String genre : genres) {					
				for (Status status: statuses) {
					List<PuzzleInfoJdo> queryResult;
					if( genre == null ) {
						if( status == null )
							queryResult = (List<PuzzleInfoJdo>)query.execute();
						else
							queryResult = (List<PuzzleInfoJdo>)query.execute(status.toString());
					} 
					else {
						if( status == null )
							queryResult = (List<PuzzleInfoJdo>)query.execute(genre);
						else
							queryResult = (List<PuzzleInfoJdo>)query.execute(genre,status.toString());
					}						
						
					mergeInto( result, queryResult );
				}
			}
		}
		finally {
			pm.close();
		}
		

	    if( genres.size() == 1 && genres.get(0) == null )
	    	genres = null;
	    if( statuses.size() == 1 && statuses.get(0) == null )
	    	statuses = null; 
	    
	    return result;
	    
	}

	

}
